extend type Query {
  user: UserInfo!
  org: OrgInfo!
  userSettings: UserSettings!
  userAttributes: UserAttributes!
  orgUsers: [UserInfo!]!
  cluster(id: ID!): ClusterInfo!
  clusterByName(name: String!): ClusterInfo!
  clusters: [ClusterInfo!]!
  autocomplete(input: String, cursorPos: Int, action: AutocompleteActionType, clusterUID: String): AutocompleteResult!
  autocompleteField(input: String, fieldType: AutocompleteEntityKind,
    requiredArgTypes: [AutocompleteEntityKind], clusterUID: String): AutocompleteFieldResult!

  # Scriptmgr endpoints, refer to docs in cloudapi.proto
  liveViews: [LiveViewMetadata!]!
  liveViewContents(id: ID!): LiveViewContents!
  scripts: [ScriptMetadata!]!
  scriptContents(id: ID!): ScriptContents!

  # Deploy keys
  deploymentKeys: [DeploymentKeyMetadata!]!
  deploymentKey(id: ID!): DeploymentKey!

  # API keys
  apiKeys: [APIKeyMetadata!]!
  apiKey(id: ID!): APIKey!

  # Plugin
  plugins(kind: PluginKind): [Plugin!]!
  retentionPluginInfo(id: String!, pluginVersion: String!): PluginInfo!
  # This will be replaced by retentionPluginConfig once all consumers have been updated.
  orgRetentionPluginConfig(id: String!): [PluginConfig!]!
  retentionPluginConfig(id: String!): RetentionPluginConfig!
  retentionScripts: [RetentionScript!]!
  retentionScript(id: String!): DetailedRetentionScript!
}

extend type Mutation {
  CreateCluster: ClusterInfo @deprecated(reason: "Clusters are now created via px deploy")
  CreateDeploymentKey: DeploymentKey!
  DeleteDeploymentKey(id: ID!): Boolean!
  CreateAPIKey: APIKey!
  DeleteAPIKey(id: ID!): Boolean!
  UpdateUserSettings(settings: EditableUserSettings!): UserSettings!
  SetUserAttributes(attributes: EditableUserAttributes!): UserAttributes!
  DeleteUser: Boolean!
  InviteUser(email: String!, firstName: String!, lastName: String!): UserInvite!
  UpdateUserPermissions(userID: ID!, userPermissions: EditableUserPermissions!): UserInfo!
  CreateOrg(orgName: String!): ID!
  UpdateOrgSettings(orgID: ID!, orgSettings: EditableOrgSettings!): OrgInfo!
  CreateInviteToken(orgID: ID!): String!
  RevokeAllInviteTokens(orgID: ID!): Boolean!
  RemoveUserFromOrg(userID: ID!): Boolean!

  # Plugin
  UpdateRetentionPluginConfig(id: String!, enabled: Boolean, enabledVersion: String, configs: EditablePluginConfigs!): Boolean!
  UpdateRetentionScript(id: ID!, script: EditableRetentionScript): Boolean!
  CreateRetentionScript(script: EditableRetentionScript): ID!
  DeleteRetentionScript(id: ID!): Boolean!
}

type UserInfo {
  id: ID!
  name: String!
  email: String!
  picture: String!
  orgName: String!
  orgID: String!
  isApproved: Boolean!
}

type IDEPath {
  IDEName: String!
  path: String!
}

type OrgInfo {
  id: ID!
  name: String!
  domainName: String!
  enableApprovals: Boolean!
  idePaths: [IDEPath!]!
}

type UserSettings {
  analyticsOptout: Boolean!
  id: ID!
}

type UserAttributes {
  tourSeen: Boolean!
  id: ID!
}

input EditableUserAttributes {
  tourSeen: Boolean
}

input EditableUserSettings {
  analyticsOptout: Boolean
}

type APIKeyMetadata {
  id: ID!
  createdAtMs: Float!
  desc: String!
}

type APIKey {
  id: ID!
  key: String!
  createdAtMs: Float!
  desc: String!
}

type DeploymentKeyMetadata {
  id: ID!
  createdAtMs: Float!
  desc: String!
}

type DeploymentKey {
  id: ID!
  key: String!
  createdAtMs: Float!
  desc: String!
}

enum AutocompleteEntityState {
  AES_UNKNOWN
  AES_PENDING
  AES_RUNNING
  AES_FAILED
  AES_TERMINATED
}

enum AutocompleteActionType {
  AAT_UNKNOWN
  # An edit action occurs if a user has modified the input text by inserting or deleting characters.
  # This includes typing on the keyboard and pasting commands.
  AAT_EDIT
  # A select action only occurs if a user has chosen an autocomplete suggestion. This indicates to
  # the autocomplete that it should move the user's cursor to the next appropriate tab.
  AAT_SELECT
}

enum AutocompleteEntityKind {
  AEK_UNKNOWN
  AEK_POD
  AEK_SVC
  AEK_SCRIPT
  AEK_NAMESPACE
  AEK_NODE
}

type AutocompleteSuggestion {
  kind: AutocompleteEntityKind
  name: String
  description: String
  matchedIndexes: [Int]
  state: AutocompleteEntityState
}

type TabSuggestion {
  # The index of the tab that these suggestions are for.
  tabIndex: Int
  # Whether selecting a suggestion for this tab index will make the command executable.
  executableAfterSelect: Boolean
  suggestions: [AutocompleteSuggestion]
}

type AutocompleteResult {
  # The formatted input is the input string, which has been parsed by the autocomplete to indicate
  # tabStop positions.
  formattedInput: String
  # Whether the input string is a valid, executable command.
  isExecutable: Boolean
  # All suggestions for each of the tabStops.
  tabSuggestions: [TabSuggestion]
}

type AutocompleteFieldResult {
  # The autocomplete suggestions for the input provided
  suggestions: [AutocompleteSuggestion]!
  # Whether or not the returned results are partial (true) or complete (false)
  hasAdditionalMatches: Boolean!
}

type ContainerStatus {
  name: String!
  createdAtMs: Float!
  state: String!
  message: String!
  reason: String!
  restartCount: Int!
}

type K8sEvent {
  message: String!
  firstTimeMs: Float!
  lastTimeMs: Float!
}

type PodStatus {
  name: String!
  createdAtMs: Float!
  status: String!
  message: String!
  reason: String!
  containers: [ContainerStatus!]!
  events: [K8sEvent!]!
  restartCount: Int!
}

enum ClusterStatus {
  # The default state if nothing is known.
  CS_UNKNOWN
  # The state is healthy if heartbeats are received on regular intervals and the
  # cluster is responding to requests.
  CS_HEALTHY
  # The state is unhealthy if the cluster is connected to Pixie Cloud and is providing
  # heartbeats, but isn't queryable for some reason. This resembles HTTP's 500 status.
  CS_UNHEALTHY
  # The state will go to disconnected if the GRPC connection breaks. The hope is that
  # the cluster will come back online and resume in HEALTHY state.
  CS_DISCONNECTED
  # The state is updating when the cluster is in the process of updating.
  CS_UPDATING
  # The vizier has connected, but has not sent any other further status updates about
  # whether it is healthy or updating.
  CS_CONNECTED
  # The vizier was trying to update, but failed and is now in a bad state.
  CS_UPDATE_FAILED
  # The state is degraded if the cluster is likely to be queryable but might be missing
  # data.
  CS_DEGRADED
}

type ClusterInfo {
  id: ID!
  status: ClusterStatus!
  lastHeartbeatMs: Float!
  vizierVersion: String!
  operatorVersion: String!
  clusterVersion: String!
  clusterName: String!
  prettyClusterName: String!
  clusterUID: String!
  controlPlanePodStatuses: [PodStatus!]!
  unhealthyDataPlanePodStatuses: [PodStatus!]!
  numNodes: Int!
  numInstrumentedNodes: Int!
  statusMessage: String!
  previousStatus: ClusterStatus
  previousStatusTimeMs: Float
}

type UserInvite {
  email: String!
  inviteLink: String!
}

# Refer to docs in cloudapi.proto
type LiveViewMetadata {
  id: ID!
  name: String!
  desc: String!
}

# Refer to docs in cloudapi.proto
type LiveViewContents {
  metadata: LiveViewMetadata!
  pxlContents: String!
  visJSON: String!
}

# Refer to docs in cloudapi.proto
type ScriptMetadata {
  id: ID!
  name: String!
  desc: String!
  hasLiveView: Boolean!
}

# Refer to docs in cloudapi.proto
type ScriptContents {
  metadata: ScriptMetadata!
  contents: String!
}

input EditableUserPermissions {
  isApproved: Boolean
}

input EditableOrgSettings {
  enableApprovals: Boolean
}

# Plugin-related types.

type Plugin {
  name: String!
  id: String!
  description: String!
  logo: String
  latestVersion: String!
  supportsRetention: Boolean!
  retentionEnabled: Boolean!
  enabledVersion: String
}

enum PluginKind {
  PK_UNKNOWN
  PK_RETENTION
}

type PluginConfig {
  name: String!
  value: String!
}

type PluginInfo {
  configs: [PluginConfigSchema!]!
  allowCustomExportURL: Boolean!
  allowInsecureTLS: Boolean!
  defaultExportURL: String!
}

type PluginConfigSchema {
  name: String!
  description: String!
}

input EditablePluginConfig {
  name: String!
  value: String!
}

input EditablePluginConfigs {
  configs: [EditablePluginConfig!]!
  customExportURL: String
  insecureTLS: Boolean
}

type RetentionPluginConfig {
  configs: [PluginConfig!]!
  customExportURL: String
  insecureTLS: Boolean
}

# Data retention types.

type RetentionScript {
  id: ID!
  name: String!
  description: String!
  frequencyS: Int!
  enabled: Boolean!
  clusters: [ID!]!
  pluginID: String!
  isPreset: Boolean!
}

type DetailedRetentionScript {
  id: ID!
  name: String!
  description: String!
  frequencyS: Int!
  enabled: Boolean!
  clusters: [ID!]!
  contents: String!
  pluginID: String!
  customExportURL: String
  isPreset: Boolean!
}

input EditableRetentionScript {
  name: String
  description: String
  frequencyS: Int
  enabled: Boolean
  clusters: [ID!]
  contents: String
  pluginID: String
  customExportURL: String
}
